package com.netsdk.utils;

import com.netsdk.demo.module.LoginModule;
import com.netsdk.lib.NetSDKLib;
import com.netsdk.lib.ToolKits;
import com.netsdk.lib.structure.NET_ACCESS_USER_INFO_EX;
import com.netsdk.lib.structure.NET_FLOORS_INFO;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;

import java.io.UnsupportedEncodingException;

/**
 * 智能门禁一体机 常用功能实现
 */
public class AccessControlUtil {

    /**
     * 初始化SDK并连接设备
     * @param ip 设备IP地址
     * @param port 设备端口
     * @param username 用户名
     * @param password 密码
     * @return 是否连接成功
     */
    public static boolean initAndConnect(String ip, int port, String username, String password) {
        // 初始化SDK
        LoginModule.init(null, null);
        
        // 登录设备
        boolean loginResult = LoginModule.login(ip, port, username, password);
        if (!loginResult) {
            System.out.println("连接设备失败！IP: " + ip + ", Port: " + port);
            return false;
        }
        
        System.out.println("连接设备成功！IP: " + ip + ", Port: " + port);
        return true;
    }
    
    /**
     * 断开设备连接并释放资源
     */
    public static void disconnectAndCleanup() {
        LoginModule.logout();
        LoginModule.cleanup();
        System.out.println("设备连接已断开，资源已释放");
    }

    public static void main(String[] args) {
        //打开工程，初始化.   注意：web项目中只在项目运行时启动一次即可
        LoginModule.init(null, null);
        //登录,门禁一体机
        LoginModule.login("192.168.1.128", Integer.parseInt("37777"), "admin", "sl123456");

        //TODO：------------------------------------ 实现功能 --------------------------------------
        //1、远程开门
        openDoor();

        //2、远程关门
        closeDoor();

        //3、查询门禁状态
        getDoorStatus(0);

        //4、开门记录
//        findAccessRecords();

        //5、指定数量 查询人员信息
//        findUserInfos();
        //6、通过ID 查询人员信息
        //findUserInfosByIds();

        //7、添加人员信息
//        addUserInfo();

        //8、删除人员信息
        //removeUserInfo();

        //登出,门禁一体机
        LoginModule.logout();
    }

    /**
     * 远程开门
     */
    public static void openDoor() {
        NetSDKLib.NET_CTRL_ACCESS_OPEN openInfo = new NetSDKLib.NET_CTRL_ACCESS_OPEN();
        openInfo.nChannelID = 0;
        openInfo.emOpenDoorType = NetSDKLib.EM_OPEN_DOOR_TYPE.EM_OPEN_DOOR_TYPE_REMOTE;
        Pointer pointer = new Memory(openInfo.size());
        ToolKits.SetStructDataToPointer(openInfo, pointer, 0);
        boolean ret = LoginModule.netsdk.CLIENT_ControlDeviceEx(LoginModule.m_hLoginHandle,
                NetSDKLib.CtrlType.CTRLTYPE_CTRL_ACCESS_OPEN, pointer, null, 10000);
        if (!ret) {
            System.out.println("远程开门失败！");
        }
    }

    /**
     * 远程关门
     */
    public static void closeDoor() {
        NetSDKLib.NET_CTRL_ACCESS_CLOSE closeInfo = new NetSDKLib.NET_CTRL_ACCESS_CLOSE();
        closeInfo.nChannelID = 0;
        Pointer pointer = new Memory(closeInfo.size());
        ToolKits.SetStructDataToPointer(closeInfo, pointer, 0);
        boolean ret = LoginModule.netsdk.CLIENT_ControlDeviceEx(LoginModule.m_hLoginHandle,
                NetSDKLib.CtrlType.CTRLTYPE_CTRL_ACCESS_CLOSE, pointer, null, 10000);
        if (!ret) {
            System.out.println("远程关门失败！");
        }
    }

    /**
     * 查询门禁状态
     * @param channel 门禁通道号
     * @return 门禁状态，参考 EM_NET_DOOR_STATUS_TYPE 枚举类型
     *         EM_NET_DOOR_STATUS_UNKNOWN = 0 未知
     *         EM_NET_DOOR_STATUS_OPEN = 1 门打开
     *         EM_NET_DOOR_STATUS_CLOSE = 2 门关闭
     *         EM_NET_DOOR_STATUS_BREAK = 3 门异常打开
     */
    public static int getDoorStatus(int channel) {
        NetSDKLib.NET_DOOR_STATUS_INFO doorStatusInfo = new NetSDKLib.NET_DOOR_STATUS_INFO();
        doorStatusInfo.nChannel = channel;
        
        Pointer pointer = new Memory(doorStatusInfo.size());
        ToolKits.SetStructDataToPointer(doorStatusInfo, pointer, 0);
        
        IntByReference retLen = new IntByReference(0);
        boolean ret = LoginModule.netsdk.CLIENT_QueryDevState(LoginModule.m_hLoginHandle,
                NetSDKLib.NET_DEVSTATE_DOOR_STATE, pointer, doorStatusInfo.size(), retLen, 5000);
        
        if (ret) {
            ToolKits.GetStructDataFromPointer(doorStatusInfo, pointer, 0);
            System.out.println("门禁状态查询成功，状态值: " + doorStatusInfo.emStateType);
            return doorStatusInfo.emStateType;
        } else {
            System.out.println("门禁状态查询失败！");
            return -1; // 查询失败返回-1
        }
    }

    /**
     * 出入记录  列表查询
     */
    public static void findAccessRecords() {
        //* 入参
        NetSDKLib.NET_IN_FIND_RECORD_PARAM inParam = new NetSDKLib.NET_IN_FIND_RECORD_PARAM();
        inParam.emType = NetSDKLib.EM_NET_RECORD_TYPE.NET_RECORD_ACCESSCTLCARDREC_EX;
        NetSDKLib.FIND_RECORD_ACCESSCTLCARDREC_CONDITION_EX findCondition = new NetSDKLib.FIND_RECORD_ACCESSCTLCARDREC_CONDITION_EX();
        inParam.pQueryCondition = findCondition.getPointer();
        //* 出参
        NetSDKLib.NET_OUT_FIND_RECORD_PARAM outParam = new NetSDKLib.NET_OUT_FIND_RECORD_PARAM();
        findCondition.write();
        if (LoginModule.netsdk.CLIENT_FindRecord(LoginModule.m_hLoginHandle, inParam, outParam, 5000)) {
            System.out.println("FindRecord Succeed!!!  FindHandle :" + outParam.lFindeHandle);
            findCondition.read();
            int max = 1000;//最大查询条数，可以修改
            NetSDKLib.NET_IN_FIND_NEXT_RECORD_PARAM stuFindNextInParam = new NetSDKLib.NET_IN_FIND_NEXT_RECORD_PARAM();
            NetSDKLib.NET_OUT_FIND_NEXT_RECORD_PARAM stuFindNextOutParam = new NetSDKLib.NET_OUT_FIND_NEXT_RECORD_PARAM();
            //出入记录存储对象
            NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC[] pstRecords = new NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC[max];
            for (int i = 0; i < max; i++) {
                pstRecords[i] = new NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC();
            }
            stuFindNextOutParam.pRecordList = new Memory(pstRecords[0].size() * max);
            stuFindNextOutParam.nMaxRecordNum = max;
            stuFindNextInParam.lFindeHandle = outParam.lFindeHandle;
            stuFindNextInParam.nFileCount = max;
            ToolKits.SetStructArrToPointerData(pstRecords, stuFindNextOutParam.pRecordList);
            if (LoginModule.netsdk.CLIENT_FindNextRecord(stuFindNextInParam, stuFindNextOutParam, 10000)) {
                //获取数据
                ToolKits.GetPointerDataToStructArr(stuFindNextOutParam.pRecordList, pstRecords);
                NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC pstRecord;
                for (int i = 0; i < stuFindNextOutParam.nRetRecordNum; i++) {
                    pstRecord = pstRecords[i];
                    try {
                        System.out.println("用户 ID:" + new String(pstRecord.szUserID, "GBK").trim());
                    } catch (UnsupportedEncodingException e) {
                    }
                    if (0 == pstRecord.emMethod) {
                        System.out.println("开门方式：未知");
                    } else if (1 == pstRecord.emMethod) {
                        System.out.println("开门方式：密码开锁");
                    } else if (2 == pstRecord.emMethod) {
                        System.out.println("开门方式：刷卡开锁");
                    } else if (5 == pstRecord.emMethod) {
                        System.out.println("开门方式：远程开锁");
                    } else if (7 == pstRecord.emMethod) {
                        System.out.println("开门方式：信息开锁");
                    } else if (15 == pstRecord.emMethod) {
                        System.out.println("开门方式：二维码开门");
                    } else if (16 == pstRecord.emMethod) {
                        System.out.println("开门方式：目标识别开门");
                    } else if (22 == pstRecord.emMethod) {
                        System.out.println("开门方式：UserID+密码");
                    } else {
                        System.out.println("开门方式：- " + pstRecord.emMethod);
                    }
                    System.out.println("记录时间:" + pstRecord.stuTime.toStringTime());
                    if (pstRecord.emDirection == 1) {
                        System.out.println("开门方向: 进门");
                    } else if (pstRecord.emDirection == 2) {
                        System.out.println("开门方向: 出门");
                    }
                    System.out.println();
                }
            } else {
                System.out.println("查询出入记录失败!");
            }
        }
    }


    /**
     * 查询人员信息列表
     */
    public static void findUserInfos() {
        int maxNum = 200;//要查询的数量
        //一、开始查询人员信息
        //* 入参 - 开始查询人员信息
        NetSDKLib.NET_IN_USERINFO_START_FIND pstIn = new NetSDKLib.NET_IN_USERINFO_START_FIND();
        //* 出参 - 开始查询人员信息
        NetSDKLib.NET_OUT_USERINFO_START_FIND pstOut = new NetSDKLib.NET_OUT_USERINFO_START_FIND();
        NetSDKLib.LLong lFindeHandle = LoginModule.netsdk.CLIENT_StartFindUserInfo(LoginModule.m_hLoginHandle, pstIn, pstOut, 5000);
        System.out.println("FindRecord Succeed!!!  FindHandle :" + lFindeHandle);
        //二、查询人员信息
        //* 入参 - 查询人员信息
        NetSDKLib.NET_IN_USERINFO_DO_FIND doIn = new NetSDKLib.NET_IN_USERINFO_DO_FIND();
        //* 出参 - 查询人员信息
        NetSDKLib.NET_OUT_USERINFO_DO_FIND doOut = new NetSDKLib.NET_OUT_USERINFO_DO_FIND();
        //初始化人员信息
        NetSDKLib.NET_ACCESS_USER_INFO[] users = new NetSDKLib.NET_ACCESS_USER_INFO[maxNum];
        for (int i = 0; i < maxNum; i++) {
            users[i] = new NetSDKLib.NET_ACCESS_USER_INFO();
        }
        Memory memory = new Memory(users[0].size() * maxNum);
        doIn.nCount = maxNum;
        doIn.nStartNo = 0;
        doOut.pstuInfo = memory;
        doOut.nMaxNum = maxNum;
        if (LoginModule.netsdk.CLIENT_DoFindUserInfo(lFindeHandle, doIn, doOut, 10000)) { //获取数据
            ToolKits.GetPointerDataToStructArr(doOut.pstuInfo, users);
            NetSDKLib.NET_ACCESS_USER_INFO userInfo;
            for (int i = 0; i < doOut.nRetNum; i++) {
                userInfo = users[i];
                System.out.println("人员 ID:" + new String(userInfo.szUserID).trim());
                try {
                    System.out.println("人员名称:" + new String(userInfo.szName, "GBK").trim());
                } catch (UnsupportedEncodingException e) {
                }
                if (userInfo.emUserType == 0) {
                    System.out.println("人员类型:普通用户");
                } else if (userInfo.emUserType == 4) {
                    System.out.println("人员类型:VIP用户");
                } else {
                    System.out.println("人员类型:未知");
                }
                System.out.println();
            }
        } else {
            System.out.println("查询失败！");
        }
        //三、停止用户信息查询
        if (LoginModule.netsdk.CLIENT_StopFindUserInfo(lFindeHandle)) {
            System.out.println("关闭查询成功！");
        } else {
            System.out.println("关闭查询失败！");
        }
    }


    /**
     * 根据用户 ID 获取用户信息
     */
    public static void findUserInfosByIds() {
        String[] userIDs = {"1"};//要查询的用户ID 【支持数组】
        // 获取的用户个数
        int nMaxNum = userIDs.length;
        // 用户操作类型
        int emtype = NetSDKLib.NET_EM_ACCESS_CTL_USER_SERVICE.NET_EM_ACCESS_CTL_USER_SERVICE_GET;
        // 先初始化用户信息数组
        NetSDKLib.NET_ACCESS_USER_INFO[] users = new NetSDKLib.NET_ACCESS_USER_INFO[nMaxNum];
        // 初始化返回的失败信息数组
        NetSDKLib.FAIL_CODE[] failCodes = new NetSDKLib.FAIL_CODE[nMaxNum];
        for (int i = 0; i < nMaxNum; i++) {
            NetSDKLib.NET_ACCESS_USER_INFO info = new NetSDKLib.NET_ACCESS_USER_INFO();
            int size = new NET_FLOORS_INFO().size();
            Pointer floors = new Memory(size);
            floors.clear(size);
            info.pstuFloorsEx2 = floors;
            NET_ACCESS_USER_INFO_EX pstuUserInfoEx = new NET_ACCESS_USER_INFO_EX();
            Pointer pstuUserInfo = new Memory(pstuUserInfoEx.size());
            pstuUserInfo.clear(pstuUserInfoEx.size());
            info.pstuUserInfoEx = pstuUserInfo;
            users[i] = info;
            failCodes[i] = new NetSDKLib.FAIL_CODE();
        }
        //* 入参 NET_IN_ACCESS_USER_SERVICE_GET
        NetSDKLib.NET_IN_ACCESS_USER_SERVICE_GET stIn = new NetSDKLib.NET_IN_ACCESS_USER_SERVICE_GET();
        // 用户 ID 个数
        stIn.nUserNum = userIDs.length;
        // 用户 ID
        for (int i = 0; i < userIDs.length; i++) {
            System.arraycopy(userIDs[i].getBytes(), 0,
                    stIn.szUserIDs[i].szUserID, 0, userIDs[i].getBytes().length);
        }
        //* 出参 NET_OUT_ACCESS_USER_SERVICE_GET
        NetSDKLib.NET_OUT_ACCESS_USER_SERVICE_GET stOut = new NetSDKLib.NET_OUT_ACCESS_USER_SERVICE_GET();
        stOut.nMaxRetNum = nMaxNum;
        stOut.pUserInfo = new Memory(users[0].size() * nMaxNum); // 申请内存
        stOut.pUserInfo.clear(users[0].size() * nMaxNum);
        stOut.pFailCode = new Memory(failCodes[0].size() * nMaxNum); // 申请内存
        stOut.pFailCode.clear(failCodes[0].size() * nMaxNum);
        ToolKits.SetStructArrToPointerData(users, stOut.pUserInfo);
        ToolKits.SetStructArrToPointerData(failCodes, stOut.pFailCode);
        stIn.write();
        stOut.write();
        if (LoginModule.netsdk.CLIENT_OperateAccessUserService(LoginModule.m_hLoginHandle, emtype,
                stIn.getPointer(), stOut.getPointer(), 3000)) {
            // 将指针转为具体的信息
            ToolKits.GetPointerDataToStructArr(stOut.pUserInfo, users);
            ToolKits.GetPointerDataToStructArr(stOut.pFailCode, failCodes);
            /**
             * 打印具体的信息
             */
            NetSDKLib.NET_ACCESS_USER_INFO userInfo;
            for (int i = 0; i < nMaxNum; i++) {
                userInfo = users[i];
                System.out.println("人员 ID:" + new String(userInfo.szUserID).trim());
                try {
                    System.out.println("人员名称:" + new String(userInfo.szName, "GBK").trim());
                } catch (UnsupportedEncodingException e) {
                }
                if (userInfo.emUserType == 0) {
                    System.out.println("人员类型:普通用户");
                } else if (userInfo.emUserType == 4) {
                    System.out.println("人员类型:VIP用户");
                } else {
                    System.out.println("人员类型:未知");
                }
                System.out.println("[" + i + "]查询用户结果：" + failCodes[i].nFailCode);
                System.out.println();
            }
        } else {
            System.out.println("查询用户失败");
        }
    }


    /**
     * 添加人员信息
     */
    public static void addUserInfo() {
        int emtype = NetSDKLib.NET_EM_ACCESS_CTL_USER_SERVICE.NET_EM_ACCESS_CTL_USER_SERVICE_INSERT;
        // 先初始化用户信息数组
        NetSDKLib.NET_ACCESS_USER_INFO user = new NetSDKLib.NET_ACCESS_USER_INFO();
        //初始化错误码接受
        NetSDKLib.FAIL_CODE failCode = new NetSDKLib.FAIL_CODE();
        //* 入参 NET_IN_ACCESS_USER_SERVICE_INSERT
        NetSDKLib.NET_IN_ACCESS_USER_SERVICE_INSERT pstInParam = new NetSDKLib.NET_IN_ACCESS_USER_SERVICE_INSERT();
        //* 出参 NET_OUT_ACCESS_USER_SERVICE_INSERT
        NetSDKLib.NET_OUT_ACCESS_USER_SERVICE_INSERT pstOutParam = new NetSDKLib.NET_OUT_ACCESS_USER_SERVICE_INSERT();
        pstInParam.nInfoNum = 1;
        pstInParam.pUserInfo = user.getPointer();
        pstOutParam.nMaxRetNum = 1;
        pstOutParam.pFailCode = failCode.getPointer();
        //TODO:  --------------------------- 设置用户信息 start ---------------------------
        user.emUserType = 0;//普通用户
        user.nUserStatus = 0;//0:正常/1:异常
        user.emSex = NetSDKLib.NET_ACCESSCTLCARD_SEX.NET_ACCESSCTLCARD_SEX_MALE;//性别   0：未知/1：男/2：女
        NetSDKLib.NET_TIME netTime = new NetSDKLib.NET_TIME();
        netTime.setTime(2037, 12, 31, 0, 0, 0);//2049-12-31
        user.stuValidEndTime = netTime;//有效期
        try {
            user.szUserID = new String("3").getBytes("GBK");//编号
            user.szName = new String("mingmars").getBytes("GBK");//用户名
            user.szPsw = new String("123").getBytes("GBK");//密码
            user.szDepartment = new String("研发部").getBytes("GBK");//部门
            user.szCitizenAddress = new String("410225199011014112").getBytes("GBK"); //证件号码
        } catch (UnsupportedEncodingException e) {
        }
        //TODO:  --------------------------- 设置用户信息 end ---------------------------
        user.write();
        failCode.write();
        pstInParam.write();
        pstOutParam.write();
        if (LoginModule.netsdk.CLIENT_OperateAccessUserService(LoginModule.m_hLoginHandle, emtype,
                pstInParam.getPointer(), pstOutParam.getPointer(), 3000)) {
            System.out.println("添加用户成功！");
            user.read();
            failCode.read();
            System.out.println("failCode:" + failCode.nFailCode);
        } else {
            System.out.println("添加用户失败！");
        }
    }


    /**
     * 删除用户信息
     */
    public static void removeUserInfo() {
        //将要删除的人员信息ID
        String[] userIDs = {"123456789"};
        // 获取的用户个数
        int nMaxNum = userIDs.length;
        // 获取用户
        int emtype = NetSDKLib.NET_EM_ACCESS_CTL_USER_SERVICE.NET_EM_ACCESS_CTL_USER_SERVICE_REMOVE;
        // 先初始化用户信息数组
        NetSDKLib.NET_ACCESS_USER_INFO[] users = new NetSDKLib.NET_ACCESS_USER_INFO[nMaxNum];
        // 初始化返回的失败信息数组
        NetSDKLib.FAIL_CODE[] failCodes = new NetSDKLib.FAIL_CODE[nMaxNum];
        for (int i = 0; i < nMaxNum; i++) {
            NetSDKLib.NET_ACCESS_USER_INFO info = new NetSDKLib.NET_ACCESS_USER_INFO();
            int size = new NET_FLOORS_INFO().size();
            Pointer floors = new Memory(size);
            floors.clear(size);
            info.pstuFloorsEx2 = floors;
            NET_ACCESS_USER_INFO_EX pstuUserInfoEx = new NET_ACCESS_USER_INFO_EX();
            Pointer pstuUserInfo = new Memory(pstuUserInfoEx.size());
            pstuUserInfo.clear(pstuUserInfoEx.size());
            info.pstuUserInfoEx = pstuUserInfo;
            users[i] = info;
            failCodes[i] = new NetSDKLib.FAIL_CODE();
        }
        //* 入参 NET_IN_ACCESS_USER_SERVICE_REMOVE
        NetSDKLib.NET_IN_ACCESS_USER_SERVICE_REMOVE pstInParam = new NetSDKLib.NET_IN_ACCESS_USER_SERVICE_REMOVE();
        // 用户 ID 个数
        pstInParam.nUserNum = userIDs.length;
        // 用户 ID
        for (int i = 0; i < userIDs.length; i++) {
            System.arraycopy(userIDs[i].getBytes(), 0, pstInParam.szUserIDs[i].szUserID, 0, userIDs[i].getBytes().length);
        }
        //* 出参 NET_OUT_ACCESS_USER_SERVICE_REMOVE
        NetSDKLib.NET_OUT_ACCESS_USER_SERVICE_REMOVE pstOutParam = new NetSDKLib.NET_OUT_ACCESS_USER_SERVICE_REMOVE();
        pstOutParam.nMaxRetNum = nMaxNum;
        pstOutParam.pFailCode = new Memory(failCodes[0].size() * nMaxNum); // 申请内存
        pstOutParam.pFailCode.clear(failCodes[0].size() * nMaxNum);
        ToolKits.SetStructArrToPointerData(failCodes, pstOutParam.pFailCode);
        pstInParam.write();
        pstOutParam.write();
        if (LoginModule.netsdk.CLIENT_OperateAccessUserService(LoginModule.m_hLoginHandle, emtype,
                pstInParam.getPointer(), pstOutParam.getPointer(), 3000)) {
            // 将指针转为具体的信息
            ToolKits.GetPointerDataToStructArr(pstOutParam.pFailCode, failCodes);
            /**
             * 打印具体的信息
             */
            for (int i = 0; i < nMaxNum; i++) {
                System.out.println("[" + i + "]删除用户信息,操作结果：" + failCodes[i].nFailCode);
            }
        } else {
            System.out.println("删除用户信息,操作失败！");
        }
    }


}

